#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <algorithm>
#include <sys/poll.h>
#include "include/TcpSocket.hpp"
#include "include/Log.hpp"

const static int default_port = 9090;
const static int default_num = 1024;

class PollServer
{
public:
    PollServer(int port = default_port): _port(port), _listen_sock(new TcpSocket()), _isRunning(false), _num(default_num)
    {
        _listen_sock->createListenSocket(_port);
        _rfds = new struct pollfd[_num];
        for(int i = 0; i < _num; i++)
        {
            _rfds[i].fd = -1;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }
        _rfds[0].fd = _listen_sock->getSocketFd();
        _rfds[0].events |= POLLIN;
    }
    
    void start()
    {
        _isRunning = true;
        while(_isRunning)
        {
            int timeout = 1000;
            int n = poll(_rfds, _num, timeout);
            if(n == 0) 
            {
                log.message(INFO, "select timeout...");
            }
            else if(n < 0)
            {
                log.message(ERROR, "select error...");
            }
            else
            {
                eventHandler(); //事件派发
                log.message(INFO, "select success...");
            }
        }
        _isRunning = false;
    }

    void stop()
    {
        _isRunning = false;
    }

    ~PollServer()
    {
        delete[] _rfds;
    }
private:
    void eventHandler()
    {
        for(int i = 0; i < _num; i++) //遍历fd
        {
            if(_rfds[i].fd != -1) //判断合法性
            {
                int fd = _rfds[i].fd;
                short revents = _rfds[i].revents;

                if(revents & POLLIN) //是否就绪
                {
                    if(fd == _listen_sock->getSocketFd()) //连接到来
                    {
                        log.message(INFO, "get a new link");
                        std::string clientIp;
                        uint16_t clientPort;
                        Socket* connect_sock = _listen_sock->accept(&clientIp, &clientPort);
                        if(connect_sock == nullptr)
                        {
                            log.message(ERROR, "accept error...");
                            continue;
                        }
                        log.message(INFO, "[%s:%d], fd:%d, new client is connected...", clientIp.c_str(), clientPort, connect_sock->getSocketFd());

                        // 连接建立后，若想读写，仍需先让poll等
                        bool canAdd = false;
                        for(int pos = 0; pos < _num; pos++) 
                        {
                            if(_rfds[pos].fd == -1)
                            {
                                _rfds[pos].fd = connect_sock->getSocketFd();
                                _rfds[pos].events = POLLIN;
                                canAdd = true;
                                break;
                            }
                        }
                        if(canAdd = false)
                        {
                            delete connect_sock;
                            log.message(WARN, "fd set is full...");
                        }
                    }
                    else //数据到来
                    {
                        char buffer[1024];
                        ssize_t n = read(fd, buffer, sizeof(buffer)-1);
                        if(n > 0)
                        {
                            buffer[n] = '\0';
                            std::cout << "echo# " << buffer << std::endl;
                        }
                        else
                        {
                            close(fd);
                            _rfds[i].fd = -1; //取消poll的关心
                            _rfds[i].events = 0;
                            _rfds[i].revents = 0;
                        }
                    }
                }
            }
        }
    }
private:
    int _port;
    std::unique_ptr<Socket> _listen_sock;
    bool _isRunning;
    struct pollfd* _rfds;
    int _num;
};